home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / vm / ds5000.md / vm3maxAsm.s < prev    next >
Encoding:
Text File  |  1992-12-19  |  23.2 KB  |  996 lines

  1. /* vmPmaxAsm.s -
  2.  *
  3.  *    Subroutines to access PMAX virtual memory mapping hardware.
  4.  *
  5.  * Copyright (C) 1989 Digital Equipment Corporation.
  6.  * Permission to use, copy, modify, and distribute this software and
  7.  * its documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appears in all copies.  
  9.  * Digital Equipment Corporation makes no representations about the
  10.  * suitability of this software for any purpose.  It is provided "as is"
  11.  * without express or implied warranty.
  12.  *
  13.  * $Header: /cdrom/src/kernel/Cvsroot/kernel/vm/ds5000.md/vm3maxAsm.s,v 1.5 92/09/08 12:29:56 shirriff Exp $ SPRITE (DECWRL)
  14.  */
  15.  
  16. #include "vm3maxConst.h"
  17. #include "machAsmDefs.h"
  18. #include <regdef.h>
  19.  
  20.  
  21. /*
  22.  *--------------------------------------------------------------------------
  23.  *
  24.  * VmMachWriteTLB --
  25.  *
  26.  *    Write the given entry into the TLB.
  27.  *
  28.  *    VmMachWriteTLB(lowEntry, highEntry)
  29.  *        unsigned    lowEntry;
  30.  *        unsigned    highEntry;
  31.  *
  32.  *    Results:
  33.  *        Returns the old index corresponding to the high register.
  34.  *
  35.  *    Side effects:
  36.  *        TLB entry set.
  37.  *
  38.  *--------------------------------------------------------------------------
  39.  */
  40. LEAF(VmMachWriteTLB)
  41. .set noreorder
  42.     mfc0    t0, VMMACH_TLB_HI    # Save the high register because this
  43.     nop                    #   contains the current PID.
  44.     mtc0    a1, VMMACH_TLB_HI    # Store into the high register.
  45.     nop
  46.     tlbp                # Probe for value.
  47.     mfc0    v0, VMMACH_TLB_INDEX    # See what index we got.  This value
  48.                     #   is returned as the result of this
  49.                     #   procedure.
  50.     mtc0    a0, VMMACH_TLB_LOW    # Set the low register.
  51.     nop
  52.     bltz    v0, 1f            # index < 0 means not found
  53.     nop
  54.     tlbwi                # Reuse the entry that we found
  55.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID.
  56.     j        ra            
  57.     nop
  58. 1:  tlbwr                # Write a random entry.
  59.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID
  60.     j        ra
  61.     nop
  62. .set reorder
  63. END(VmMachWriteTLB)
  64.  
  65.  
  66. /*
  67.  *--------------------------------------------------------------------------
  68.  *
  69.  * VmMachWriteIndexedTLB --
  70.  *
  71.  *    Write the given entry into the TLB at the given index.
  72.  *
  73.  *    VmMachWriteTLB(index, lowEntry, highEntry)
  74.  *        unsigned    index;
  75.  *        unsigned    lowEntry;
  76.  *        unsigned    highEntry;
  77.  *
  78.  *    Results:
  79.  *        None.
  80.  *
  81.  *    Side effects:
  82.  *        TLB entry set.
  83.  *
  84.  *--------------------------------------------------------------------------
  85.  */
  86. LEAF(VmMachWriteIndexedTLB)
  87. .set noreorder
  88.     mfc0    t0, VMMACH_TLB_HI    # Save the high register because this
  89.                     #   contains the current PID.
  90.  
  91.     sll        a0, a0, VMMACH_TLB_INDEX_SHIFT
  92.     mtc0    a0, VMMACH_TLB_INDEX    # Set the index.
  93.     mtc0    a1, VMMACH_TLB_LOW    # Set up entry low.
  94.     mtc0    a2, VMMACH_TLB_HI    # Set up entry high.
  95.     nop
  96.     tlbwi                # Write the TLB
  97.  
  98.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID.
  99.  
  100.     j        ra
  101.     nop
  102. .set reorder
  103. END(VmMachWriteIndexedTLB)
  104.  
  105. /* 
  106.  *--------------------------------------------------------------------------
  107.  *
  108.  * VmMachFlushPIDFromTLB --
  109.  *
  110.  *    Flush all pages for the given PID from the TLB.
  111.  *
  112.  *    VmMachFlushPIDFromTLB(pid)
  113.  *        int        pid;
  114.  *
  115.  *    Results:
  116.  *        None.
  117.  *
  118.  *    Side effects:
  119.  *        All entries corresponding to this PID are flushed.
  120.  *
  121.  *--------------------------------------------------------------------------
  122.  */
  123. LEAF(VmMachFlushPIDFromTLB)
  124. .set noreorder
  125.     subu    sp, sp, STAND_FRAME_SIZE
  126.     sw        ra, STAND_RA_OFFSET(sp)
  127.     sw        a0, STAND_FRAME_SIZE(sp)
  128.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  129.  
  130.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  131.     sll        a0, a0, VMMACH_TLB_PID_SHIFT    # Align the pid to flush.
  132.  
  133. /*
  134.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  135.  */
  136.     li        t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
  137.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  138.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  139.  
  140. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register
  141.     addu    t1, t1, t2            # Increment index.
  142.     tlbr                    # Read from the TLB    
  143.     mfc0    t4, VMMACH_TLB_HI        # Fetch the hi register.
  144.     nop
  145.     and        t4, t4, a0            # See if the pids match.
  146.     bne        t4, a0, 2f
  147.     li        t4, VMMACH_PHYS_CACHED_START
  148.     mtc0    t4, VMMACH_TLB_HI        # Mark entry high as invalid
  149.     mtc0    zero, VMMACH_TLB_LOW        # Zero out entry low.
  150.     nop
  151.     tlbwi                    # Write the entry.
  152. 2:
  153.     bne        t1, t3, 1b
  154.     nop
  155.  
  156.     mtc0    t0, VMMACH_TLB_HI
  157.     addu    sp, sp, STAND_FRAME_SIZE
  158.  
  159.     j        ra
  160.     nop
  161. .set reorder
  162. END(VmMachFlushPIDFromTLB)
  163.  
  164.  
  165. /* 
  166.  *--------------------------------------------------------------------------
  167.  *
  168.  * VmMachFlushTLB --
  169.  *
  170.  *    Flush the TLB.
  171.  *
  172.  *    VmMachFlushTLB()
  173.  *
  174.  *    Results:
  175.  *        None.
  176.  *
  177.  *    Side effects:
  178.  *       The TLB is flushed.
  179.  *
  180.  *--------------------------------------------------------------------------
  181.  */
  182. LEAF(VmMachFlushTLB)
  183. .set noreorder
  184.     subu    sp, sp, STAND_FRAME_SIZE
  185.     sw        ra, STAND_RA_OFFSET(sp)
  186.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  187.  
  188.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  189.     li        t1, VMMACH_PHYS_CACHED_START
  190.     mtc0    t1, VMMACH_TLB_HI        # Invalidate hi entry.
  191.     mtc0    zero, VMMACH_TLB_LOW        # Zero out entry low.
  192.  
  193. /*
  194.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  195.  */
  196.     li        t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
  197.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  198.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  199.  
  200. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register.
  201.     addu    t1, t1, t2            # Increment index.
  202.     tlbwi                    # Write the TLB entry.
  203.     bne        t1, t3, 1b
  204.     nop
  205.  
  206.     mtc0    t0, VMMACH_TLB_HI        # Restore the PID
  207.     addu    sp, sp, STAND_FRAME_SIZE
  208.  
  209.     j        ra
  210.     nop
  211. .set reorder
  212. END(VmMachFlushTLB)
  213.  
  214.  
  215. /* 
  216.  *--------------------------------------------------------------------------
  217.  *
  218.  * VmMachFlushPageFromTLB --
  219.  *
  220.  *    Flush the given page from the TLB for the given process.
  221.  *
  222.  *    VmMachFlushPageFromTLB(pid, page)
  223.  *
  224.  *    Results:
  225.  *        None.
  226.  *
  227.  *    Side effects:
  228.  *       The process's page is flushed from the TLB.
  229.  *
  230.  *--------------------------------------------------------------------------
  231.  */
  232. LEAF(VmMachFlushPageFromTLB)
  233. .set noreorder
  234.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  235.  
  236.     sll        a0, a0, VMMACH_TLB_PID_SHIFT        # Align pid
  237.     sll        a1, a1, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  238.     or        t1, a0, a1                # Set up entry.
  239.     mtc0    t1, VMMACH_TLB_HI            # Put into high reg.
  240.     nop
  241.     tlbp                        # Probe for the entry.
  242.     mfc0    v0, VMMACH_TLB_INDEX            # See what we got
  243.     li        t1, VMMACH_PHYS_CACHED_START        # Load invalid entry.
  244.     bltz    v0, 1f                    # index < 0 => !found
  245.     nop
  246.     mtc0    t1, VMMACH_TLB_HI            # Prepare index hi.
  247.     mtc0    zero, VMMACH_TLB_LOW            # Prepare index lo.
  248.     nop
  249.     tlbwi
  250.  
  251. 1:
  252.     mtc0    t0, VMMACH_TLB_HI            # Restore the PID
  253.     j        ra
  254.     nop
  255.  
  256. .set reorder
  257. END(VmMachFlushPageFromTLB)
  258.  
  259.  
  260. /* 
  261.  *--------------------------------------------------------------------------
  262.  *
  263.  * VmMachClearTLBModBit --
  264.  *
  265.  *    Clear the modified bit for the given <pid, page> pair.
  266.  *
  267.  *    VmMachClearTLBModBit(pid, page)
  268.  *
  269.  *    Results:
  270.  *        None.
  271.  *
  272.  *    Side effects:
  273.  *       The process's page is flushed from the TLB.
  274.  *
  275.  *--------------------------------------------------------------------------
  276.  */
  277. LEAF(VmMachClearTLBModBit)
  278. .set noreorder
  279.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  280.  
  281.     sll        a0, a0, VMMACH_TLB_PID_SHIFT        # Align pid
  282.     sll        a1, a1, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  283.     or        t1, a0, a1                # Set up entry.
  284.     mtc0    t1, VMMACH_TLB_HI            # Put into high reg.
  285.     nop
  286.     tlbp                        # Probe for the entry.
  287.     mfc0    v0, VMMACH_TLB_INDEX            # See what we got
  288.     nop
  289.     bltz    v0, 1f                    # index < 0 => !found
  290.     nop
  291.     tlbr
  292.     mfc0    t1, VMMACH_TLB_LOW            # Read out low.
  293.     nop
  294.     and        t1, t1, ~VMMACH_TLB_MOD_BIT
  295.     mtc0    t1, VMMACH_TLB_LOW            # Write index low.
  296.     nop
  297.     tlbwi                        # Write the TLB entry.
  298.  
  299. 1:
  300.     mtc0    t0, VMMACH_TLB_HI            # Restore the PID
  301.     j        ra
  302.     nop
  303.  
  304. .set reorder
  305. END(VmMachClearTLBModBit)
  306.  
  307. #ifdef notdef
  308.  
  309. /* 
  310.  *--------------------------------------------------------------------------
  311.  *
  312.  * VmMachFlushGlobalPageFromTLB --
  313.  *
  314.  *    Flush the given page from the TLB for the given process.
  315.  *
  316.  *    VmMachFlushPageFromTLB(pid, page)
  317.  *
  318.  *    Results:
  319.  *        None.
  320.  *
  321.  *    Side effects:
  322.  *       The process's page is flushed from the TLB.
  323.  *
  324.  *--------------------------------------------------------------------------
  325.  */
  326. LEAF(VmMachFlushGlobalPageFromTLB)
  327. .set noreorder
  328.     subu    sp, sp, STAND_FRAME_SIZE
  329.     sw        ra, STAND_RA_OFFSET(sp)
  330.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  331.  
  332.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  333.  
  334.     sll        t1, a0, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  335.  
  336.     addu    t2, zero, zero
  337.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  338.     li        v0, 0x80000000
  339.  
  340. 6:  mtc0    t2, VMMACH_TLB_INDEX            # Set index
  341.     nop
  342.     tlbr                        # Read an entry.
  343.     mfc0    t4, VMMACH_TLB_HI
  344.     nop
  345.     and        t4, t4, VMMACH_TLB_VIRT_PAGE_NUM
  346.     bne        t4, t1, 2f                # test for pid/vpn match
  347.     nop
  348.  
  349.     addu    v0, t2, zero
  350.     li        t4, VMMACH_PHYS_CACHED_START
  351.     mtc0    t4, VMMACH_TLB_HI            # Prepare index hi
  352.     mtc0    zero, VMMACH_TLB_LOW            # Prepare index lo
  353.     nop
  354.     tlbwi                        # Invalidate entry
  355. 2:
  356.     addu    t2, t2, 1 << VMMACH_TLB_INDEX_SHIFT
  357.     bne        t2, t3, 6b
  358.     nop
  359.  
  360. 4:  mtc0    t0, VMMACH_TLB_HI    
  361.     addu    sp, sp, STAND_FRAME_SIZE
  362.     j        ra
  363.     nop
  364.  
  365. .set reorder
  366. END(VmMachFlushGlobalPageFromTLB)
  367. #endif
  368.  
  369. /* 
  370.  *--------------------------------------------------------------------------
  371.  *
  372.  * VmMachDumpTLB --
  373.  *
  374.  *    Flush the TLB.
  375.  *
  376.  *    VmMachFlushTLB(tlbPtr)
  377.  *        unsigned *tlbPtr;
  378.  *
  379.  *    Results:
  380.  *        None.
  381.  *
  382.  *    Side effects:
  383.  *       The contents of the TLB are written to *tlbPtr.
  384.  *
  385.  *--------------------------------------------------------------------------
  386.  */
  387. LEAF(Vm_MachDumpTLB)
  388. .set noreorder
  389.     subu    sp, sp, STAND_FRAME_SIZE
  390.     sw        ra, STAND_RA_OFFSET(sp)
  391.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  392.  
  393.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  394.  
  395. /*
  396.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  397.  */
  398.     li        t1, 0
  399.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  400.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  401.  
  402. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register.
  403.     addu    t1, t1, t2            # Increment index.
  404.     tlbr                    # Read the TLB entry.
  405.     mfc0    t4, VMMACH_TLB_LOW
  406.     mfc0    t5, VMMACH_TLB_HI
  407.     sw        t4, 0(a0)
  408.     sw        t5, 4(a0)
  409.     addu    a0, a0, 8
  410.     bne        t1, t3, 1b
  411.     nop
  412.  
  413.     mtc0    t0, VMMACH_TLB_HI        # Restore the PID
  414.     addu    sp, sp, STAND_FRAME_SIZE
  415.  
  416.     j        ra
  417.     nop
  418. .set reorder
  419. END(Vm_MachDumpTLB)
  420.  
  421. /* 
  422.  *--------------------------------------------------------------------------
  423.  *
  424.  * VmMachSetPID --
  425.  *
  426.  *    Write the given pid into the TLB pid reg.
  427.  *
  428.  *    VmMachWritePID(pid)
  429.  *        int        pid;
  430.  *
  431.  *    Results:
  432.  *        None.
  433.  *
  434.  *    Side effects:
  435.  *        PID set in the entry hi register.
  436.  *
  437.  *--------------------------------------------------------------------------
  438.  */
  439.     .globl VmMachSetPID
  440. VmMachSetPID:
  441.     sll        a0, a0, 6        # Reg 4 <<= 6 to put PID in right spot
  442.     mtc0    a0, VMMACH_TLB_HI    # Write the hi reg value
  443.     j        ra
  444.  
  445.  
  446. /*
  447.  * ----------------------------------------------------------------------
  448.  *
  449.  * Vm_Copy{In,Out}
  450.  *
  451.  *    Copy numBytes from *sourcePtr in to *destPtr.
  452.  *    This routine is optimized to do transfers when sourcePtr and 
  453.  *    destPtr are both 4-byte aligned.
  454.  *
  455.  *    ReturnStatus
  456.  *    Vm_Copy{In,Out}(numBytes, sourcePtr, destPtr)
  457.  *        register int numBytes;      * The number of bytes to copy *
  458.  *        Address sourcePtr;          * Where to copy from. *
  459.  *        Address destPtr;            * Where to copy to. *
  460.  *
  461.  *    NOTE: The trap handler assumes that this routine does not push anything
  462.  *          onto the stack.  It uses this fact to allow it to return to the
  463.  *          caller of this routine upon an address fault.  If you must push
  464.  *          something onto the stack then you had better go and modify 
  465.  *          "CallTrapHandler" in asmDefs.h appropriately.
  466.  *
  467.  * Results:
  468.  *    Returns SUCCESS if the copy went OK (which is almost always).  If
  469.  *    a bus error (other than a page fault) occurred while reading or
  470.  *    writing user memory, then SYS_ARG_NO_ACCESS is returned (this return
  471.  *    occurs from the trap handler, rather than from this procedure).
  472.  *
  473.  * Side effects:
  474.  *    The area that destPtr points to is modified.
  475.  *
  476.  * ----------------------------------------------------------------------
  477.  */
  478.     .globl VmMachDoCopy
  479.     .globl Vm_CopyIn
  480. VmMachDoCopy:
  481. Vm_CopyIn:
  482. /*
  483.  * The number of bytes was passed in in r4, the source in r5, and the dest
  484.  * in r6.
  485.  *
  486.  * If the source or dest are not 4 byte aligned then everything must be
  487.  * done as byte copies.
  488.  */
  489.  
  490. gotArgs:
  491.     or        t0, a1, a2
  492.     andi    t0, t0, 3
  493.     blez    t0, 1f
  494.     j        3f
  495.  
  496. /*
  497.  * Do as many 64-byte copies as possible.
  498.  */
  499.  
  500. 1:
  501.     subu    t0, a0, 64
  502.     bltz    t0, 2f
  503.     lw        t0, 0(a1)
  504.     lw        t1, 4(a1)
  505.     sw        t0, 0(a2)
  506.     sw        t1, 4(a2)
  507.     lw        t0, 8(a1)
  508.     lw        t1, 12(a1)
  509.     sw        t0, 8(a2)
  510.     sw        t1, 12(a2)
  511.     lw        t0, 16(a1)
  512.     lw        t1, 20(a1)
  513.     sw        t0, 16(a2)
  514.     sw        t1, 20(a2)
  515.     lw        t0, 24(a1)
  516.     lw        t1, 28(a1)
  517.     sw        t0, 24(a2)
  518.     sw        t1, 28(a2)
  519.     lw        t0, 32(a1)
  520.     lw        t1, 36(a1)
  521.     sw        t0, 32(a2)
  522.     sw        t1, 36(a2)
  523.     lw        t0, 40(a1)
  524.     lw        t1, 44(a1)
  525.     sw        t0, 40(a2)
  526.     sw        t1, 44(a2)
  527.     lw        t0, 48(a1)
  528.     lw        t1, 52(a1)
  529.     sw        t0, 48(a2)
  530.     sw        t1, 52(a2)
  531.     lw        t0, 56(a1)
  532.     lw        t1, 60(a1)
  533.     sw        t0, 56(a2)
  534.     sw        t1, 60(a2)
  535.     subu    a0, a0, 64
  536.     addu    a1, a1, 64
  537.     addu    a2, a2, 64
  538.     j        1b
  539.  
  540. /*
  541.  * Do 4 byte copies.
  542.  */
  543. 2:
  544.     subu    t0, a0, 4
  545.     bltz    t0, 3f
  546.     lw        t0, 0(a1)
  547.     sw        t0, 0(a2)
  548.     subu    a0, a0, 4
  549.     addu    a1, a1, 4
  550.     addu    a2, a2, 4
  551.     j        2b
  552.  
  553. /*
  554.  * Do one byte copies until done.
  555.  */
  556.  
  557. 3:
  558.     beq        a0, zero, 4f
  559.     lb        t0, 0(a1)
  560.     sb        t0, 0(a2)
  561.     subu    a0, a0, 1
  562.     addu    a1, a1, 1
  563.     addu    a2, a2, 1
  564.     j        3b
  565.  
  566. /* 
  567.  * Return.
  568.  */
  569. 4: 
  570.     li        v0, 0
  571.     j        ra
  572.  
  573. /* 
  574.  * Vm_CopyOut is just like Vm_CopyIn except that it checks to make sure
  575.  * that the destination is in the user area (otherwise this would be a
  576.  * trap door to write to kernel space).
  577.  */
  578.  
  579.     .globl Vm_CopyOut
  580. .ent Vm_CopyOut
  581. Vm_CopyOut:
  582. /*
  583.  * If a2 is < 0 then it is has the sign bit set which means its in the
  584.  * kernel's VAS.
  585.  */
  586.     bltz    a2, 5f
  587.     j        gotArgs
  588.  
  589. /*
  590.  * User address out of range.  Check for a zero byte count before
  591.  * returning an error, though;  there appear to be kernel routines
  592.  * that call Vm_CopyOut with a zero count but bogus other arguments.
  593.  */
  594.  
  595. 5:
  596.     blez    a0, 6f
  597.     lui        v0, 2
  598.     j        ra
  599. 6:  li        v0, 0
  600.     j        ra
  601. .end
  602.  
  603.  
  604. /*
  605.  * ----------------------------------------------------------------------
  606.  *
  607.  * Vm_StringNCopy
  608.  *
  609.  *    Copy the NULL terminated string from *sourcePtr to *destPtr up
  610.  *    numBytes worth of bytes.
  611.  *
  612.  *    void
  613.  *    Vm_StringNCopy(numBytes, sourcePtr, destPtr, bytesCopiedPtr)
  614.  *        register int numBytes;      * The number of bytes to copy *
  615.  *        Address sourcePtr;          * Where to copy from. *
  616.  *        Address destPtr;            * Where to copy to. *
  617.  *        int    *bytesCopiedPtr;    * Number of bytes copied. *
  618.  *
  619.  *    NOTE: The trap handler assumes that this routine does not push anything
  620.  *          onto the stack.  It uses this fact to allow it to return to the
  621.  *          caller of this routine upon an address fault.  If you must push
  622.  *          something onto the stack then you had better go and modify 
  623.  *          "CallTrapHandler" in asmDefs.h appropriately.
  624.  *
  625.  * Results:
  626.  *    Normally returns SUCCESS.  If a non-recoverable bus error occurs,
  627.  *    then the trap handler fakes up a SYS_ARG_NO_ACCESS return from
  628.  *    this procedure.
  629.  *
  630.  * Side effects:
  631.  *    The area that destPtr points to is modified and *bytesCopiedPtr 
  632.  *    contains the number of bytes copied.
  633.  *
  634.  * ----------------------------------------------------------------------
  635.  */
  636.     .globl  Vm_StringNCopy
  637. Vm_StringNCopy:
  638.     addu    t2, a0, 0        # Save the number of bytes
  639. 1:
  640.     lb        t0, 0(a1)
  641.     sb        t0, 0(a2)
  642.     beq        t0, zero, 2f
  643.     addu    a1, a1, 1
  644.     addu    a2, a2, 1
  645.     subu    a0, a0, 1
  646.     bne        a0, zero, 1b
  647. 2: 
  648.     subu    a0, t2, a0
  649.     sw        a0, 0(a3)
  650.     li        v0, 0
  651.     j        ra
  652.  
  653.  
  654. /*
  655.  * ----------------------------------------------------------------------
  656.  *
  657.  * Vm_TouchPages --
  658.  *
  659.  *    Touch the range of pages.
  660.  *
  661.  *    void
  662.  *    Vm_TouchPages(firstPage, numPages)
  663.  *        int    firstPage;    * First page to touch. *
  664.  *        int    numPages;    * Number of pages to touch. *
  665.  *
  666.  *    NOTE: The trap handler assumes that this routine does not push anything
  667.  *          onto the stack.  It uses this fact to allow it to return to the
  668.  *          caller of this routine upon an address fault.
  669.  *
  670.  * Results:
  671.  *    Returns SUCCESS if were able to touch the page (which is almost
  672.  *    always).  If a bus error (other than a page fault) occurred while 
  673.  *    reading user memory, then SYS_ARG_NO_ACCESS is returned (this return
  674.  *    occurs from the trap handler, rather than from this procedure).
  675.  *
  676.  * Side effects:
  677.  *    None.
  678.  *
  679.  * ----------------------------------------------------------------------
  680.  */
  681.     .globl Vm_TouchPages
  682. Vm_TouchPages:
  683.     sll        a0, a0, VMMACH_PAGE_SHIFT
  684. 1:
  685.     beq        a1, zero, 2f
  686.     lw        t0, 0(a0)
  687.     subu    a1, a1, 1
  688.     addu    a0, a0, VMMACH_PAGE_SIZE
  689.     j        1b
  690. 2:
  691.     j        ra
  692.  
  693.     .globl VmMachCopyEnd
  694. VmMachCopyEnd:
  695.  
  696. /*----------------------------------------------------------------------------
  697.  *
  698.  * VmMach_UTLBMiss --
  699.  *
  700.  *    Handle a user TLB miss.
  701.  *
  702.  *
  703.  * Results:
  704.  *         None.
  705.  *
  706.  * Side effects:
  707.  *    None.
  708.  *
  709.  *----------------------------------------------------------------------------
  710.  */
  711.     .globl VmMach_UTLBMiss
  712.     .ent VmMach_UTLBMiss
  713. VmMach_UTLBMiss:
  714. .set noat
  715. .set noreorder
  716.     mfc0    k0, VMMACH_TLB_HI            # Get the high val.
  717.     lui        k1, 0x8000            
  718.     sw        AT, VMMACH_SAVED_AT_OFFSET(k1)
  719. #ifndef NO_COUNTERS
  720.     lw        AT, VMMACH_UTLB_COUNT_OFFSET(k1)
  721.     nop    
  722.     addu    AT, AT, 1
  723.     sw        AT, VMMACH_UTLB_COUNT_OFFSET(k1)
  724. #endif
  725.  
  726. /*
  727.  * Make the hash key.
  728.  */
  729.     srl        k1, k0, VMMACH_PAGE_HASH_SHIFT
  730.     sll        AT, k0, VMMACH_PID_HASH_SHIFT
  731.     xor        k1, k1, AT
  732. .set at
  733.     and        k1, k1, VMMACH_HASH_MASK
  734. .set noat
  735. /*
  736.  * Load the hash table key.
  737.  */
  738.     la        AT, vmMachTLBHashTable
  739.     addu    AT, k1, AT
  740.     lw        k1, VMMACH_HASH_KEY_OFFSET(AT)
  741.     nop
  742.  
  743. /*
  744.  * Check for match.
  745.  */
  746.     beq        k1, k0, 1f
  747.     lw        k1, VMMACH_LOW_REG_OFFSET(AT)
  748.     j        SlowUTLBFault
  749. /*
  750.  * We have a match.  Restore AT and write the TLB entry.
  751.  */
  752. 1:
  753.     lui        AT, 0x8000
  754.     mtc0    k1, VMMACH_TLB_LOW
  755.     mfc0    k0, MACH_COP_0_EXC_PC
  756.     tlbwr
  757. #ifndef NO_COUNTERS
  758.     lw        k1, VMMACH_UTLB_HIT_OFFSET(AT)
  759.     nop
  760.     addu    k1, k1, 1
  761.     sw        k1, VMMACH_UTLB_HIT_OFFSET(AT)
  762. #endif
  763.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  764.     j        k0
  765.     rfe
  766.     .end VmMach_UTLBMiss
  767.  
  768.     .globl VmMach_EndUTLBMiss
  769. VmMach_EndUTLBMiss:
  770. .set reorder
  771.  
  772. /*
  773.  * We couldn't find a TLB entry.  Find out what mode we came from and call
  774.  * the appropriate handler.
  775.  */
  776. SlowUTLBFault:
  777.     lui        AT, 0x8000
  778.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  779. .set reorder
  780.     mfc0    k0, MACH_COP_0_STATUS_REG
  781.     nop
  782.     and        k0, k0, MACH_SR_KU_PREV
  783.     bne        k0, zero, 1f
  784.     j        Mach_KernGenException
  785. 1:  j        Mach_UserGenException
  786.  
  787. .set at
  788.  
  789. /*----------------------------------------------------------------------------
  790.  *
  791.  * VmMach_KernTLBException --
  792.  *
  793.  *    Handle a kernel TLB fault.
  794.  *
  795.  * Results:
  796.  *         None.
  797.  *
  798.  * Side effects:
  799.  *    None.
  800.  *
  801.  *----------------------------------------------------------------------------
  802.  */
  803. str:
  804.     .asciiz    "Error on stack @ 0x%x, pc=0x%x\n"
  805.     .globl VmMach_KernTLBException
  806.     .ent VmMach_KernTLBException, 0
  807. VmMach_KernTLBException:
  808. .set noreorder
  809. .set noat
  810.     mfc0    k0, MACH_COP_0_BAD_VADDR    # Get the faulting address
  811.     addu    k1, sp, zero
  812.     srl        k1, k1, VMMACH_PAGE_SHIFT
  813.     srl        k0, k0, VMMACH_PAGE_SHIFT
  814.     bne        k0, k1, 1f
  815.     nop
  816. /* 
  817.  * TLB faults on kernel stacks are bad news because they should be wired. 
  818.  * Call panic but which to the initial kernel stack so when panic pushes
  819.  * things on the stack when won't come right back here.
  820.  */
  821. #define    START_FRAME   ((4*4) + 4 + 4)
  822.  
  823.     la        a0, str
  824.     addu    a1, sp, zero
  825.     li        sp, MACH_CODE_START - START_FRAME
  826.     mfc0    k1, MACH_COP_0_EXC_PC        # Get the exception PC
  827.     nop
  828.     addu    a2, k1, zero
  829.     jal        panic
  830.     nop
  831.  
  832. 1:
  833.     mfc0    k0, MACH_COP_0_BAD_VADDR    # Get the faulting address
  834.     li        k1, VMMACH_VIRT_CACHED_START    # Get the lower bound
  835.     sltu    k1, k0, k1            # Compare to the lower bound
  836.     bne        k1, zero, KernGenException    #    and take a normal exception
  837.     nop                        #    if we are lower
  838.     li        k1, MACH_KERN_END        # Get the upper bound
  839.     sltu    k1, k0, k1            # Compare to the upper bound
  840.     beq        k1, zero, KernGenException    #    and take a normal 
  841.                         #    exception if we are higher.
  842.     srl        k0, VMMACH_PAGE_SHIFT        # Get the virtual page number.
  843.     li        k1, VMMACH_VIRT_CACHED_START_PAGE
  844.     subu    k0, k0, k1
  845.     lw        k1, vmMach_KernelTLBMap        # Get to map that contains
  846.                         #     the TLB entry.
  847.     sll        k0, k0, 2            # Each entry is four bytes
  848.     addu    k0, k0, k1            # Get pointer to entry.
  849.     lw        k0, 0(k0)            # Get entry
  850.     nop
  851.     beq        k0, zero, KernGenException    # If entry is zero then take
  852.                         #    a normal exception.
  853.     mtc0    k0, VMMACH_TLB_LOW        # Set the low entry.
  854.     mfc0    k1, MACH_COP_0_EXC_PC        # Get the exception PC
  855.     tlbwr                    # Write the entry out.
  856.     j        k1
  857.     rfe
  858.  
  859. KernGenException:
  860.     j        Mach_KernGenException
  861.     nop
  862.  
  863. .end VmMach_KernTLBException
  864. .set at
  865. .set reorder
  866.  
  867. /*----------------------------------------------------------------------------
  868.  *
  869.  * VmMach_TLBModException --
  870.  *
  871.  *    Handle a modified exception.
  872.  *
  873.  * Results:
  874.  *         None.
  875.  *
  876.  * Side effects:
  877.  *    None.
  878.  *
  879.  *----------------------------------------------------------------------------
  880.  */
  881.     .globl VmMach_TLBModException
  882.     .ent VmMach_TLBModException, 0
  883. VmMach_TLBModException:
  884. .set noat
  885. .set noreorder
  886.     mfc0    k0, VMMACH_TLB_HI            # Get the high val.
  887.     lui        k1, 0x8000
  888.     sw        AT, VMMACH_SAVED_AT_OFFSET(k1)
  889. #ifndef NO_COUNTERS
  890.     lw        AT, VMMACH_MOD_COUNT_OFFSET(k1)
  891.     nop    
  892.     addu    AT, AT, 1
  893.     sw        AT, VMMACH_MOD_COUNT_OFFSET(k1)
  894. #endif
  895.  
  896. /*
  897.  * Make the hash key.
  898.  */
  899.     srl        k1, k0, VMMACH_PAGE_HASH_SHIFT
  900.     sll        AT, k0, VMMACH_PID_HASH_SHIFT
  901.     xor        k1, k1, AT
  902. .set at
  903.     and        k1, k1, VMMACH_HASH_MASK
  904. .set noat
  905. /*
  906.  * Load the hash table key.
  907.  */
  908.     la        AT, vmMachTLBHashTable
  909.     addu    AT, k1, AT
  910.     lw        k1, VMMACH_HASH_KEY_OFFSET(AT)
  911.     nop
  912.  
  913. /*
  914.  * Check for match.
  915.  */
  916.     beq        k1, k0, 1f
  917.     nop
  918.     j        SlowModFault
  919.     nop
  920. /*
  921.  * We have a match.  See if we can write this page.
  922.  */
  923. 1:  
  924. #ifndef NO_COUNTERS
  925.     lui        k0, 0x8000
  926.     lw        k1, VMMACH_MOD_HIT_OFFSET(k0)
  927.     nop
  928.     addu    k1, k1, 1
  929.     sw        k1, VMMACH_MOD_HIT_OFFSET(k0)
  930. #endif
  931.  
  932.     lw        k1, VMMACH_LOW_REG_OFFSET(AT)
  933.     nop
  934.     and        k0, k1, VMMACH_TLB_ENTRY_WRITEABLE
  935.     beq        k0, zero, SlowModFault
  936.     nop
  937. /*
  938.  * Find the entry in the TLB.  It has to be there since we took a mod fault
  939.  * on it.  While were at it set the mod bit in the hash table entry.
  940.  */
  941.     tlbp
  942.     mfc0    k0, VMMACH_TLB_INDEX
  943.     or        k1, k1, VMMACH_TLB_MOD_BIT
  944.     sw        k1, VMMACH_LOW_REG_OFFSET(AT)
  945.     bltz    k0, 1f
  946.     nop
  947. /*
  948.  * Write the TLB.
  949.  */
  950.     mtc0    k1, VMMACH_TLB_LOW
  951.     nop
  952.     tlbwi
  953. /*
  954.  * Set the modified bit in the physical page array.
  955.  */
  956. .set at
  957.     lw        k0, vmMachPhysPageArr
  958.     srl        k1, k1, VMMACH_TLB_PHYS_PAGE_SHIFT
  959.     sll        k1, k1, 2
  960.     addu    k0, k0, k1
  961.     lw        k1, 0(k0)
  962.     nop
  963.     or        k1, k1, 4
  964.     sw        k1, 0(k0)
  965. .set noat
  966. /* 
  967.  * Restore AT and return.
  968.  */
  969.     mfc0    k0, MACH_COP_0_EXC_PC
  970.     lui        AT, 0x8000
  971.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  972.     j        k0
  973.     rfe
  974. 1:
  975.     break    0
  976. .set reorder
  977.  
  978. /*
  979.  * We couldn't find a TLB entry.  Find out what mode we came from and call
  980.  * the appropriate handler.
  981.  */
  982. SlowModFault:
  983.     lui        AT, 0x8000
  984.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  985. .set reorder
  986.     mfc0    k0, MACH_COP_0_STATUS_REG
  987.     nop
  988.     and        k0, k0, MACH_SR_KU_PREV
  989.     bne        k0, zero, 1f
  990.     j        Mach_KernGenException
  991. 1:  j        Mach_UserGenException
  992.  
  993. .end VmMach_TLBModException
  994. .set at
  995.  
  996.